<?php

/**
 * @fun:     decode csv
 * @author:  ZHL
 * @date:    2020-5-12
 * @version: V 1.2
 * @desc:    csv文件导入导出操作
 */
 
class ManageCSV{

    /**
     * @fun:     CSV文件导入解析成数组
     * @author:  ZHL
     * @date:    2020-3-8
     * @param string  $fileName    传入控件名
     * @return array
     */
    public function de_csv($fileName = 'file'){
        $file = $_FILES[$fileName]['tmp_name'];
        $hint = array('code'=>'0','msg'=>'Error','data'=>array());
        if(!empty($file)){
            if(is_array($file)){
                foreach($file as $v){
                    $data = $this->csv_arr($v);
                    if(!empty($data)){
                        $hint['data'] = array_merge($hint['data'],$data);
                    }
                }
            }else{
                $hint['data'] = $this->csv_arr($file);
            }
            $hint['code'] = 1;
            $hint['msg'] = 'Success';
        }else{
            $hint['code'] = 2;
            $hint['msg'] = 'Please select the CSV';
        }
        return $hint;
    }

    // 打开csv解析数据转数组
    private function csv_arr($file = ''){
        $data = array();
        $handle = fopen($file, 'r');
        $res = $this->input_csv($handle);
        if(!empty($res['data'][0][0])){
            $td = array('A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
                'AA','AB','AC','AD','AE','AF','AG','AH','AI','AJ','AK','AL','AM','AN','AO','AP','AQ','AR','AS','AT','AU','AV','AW','AX','AY','AZ',
                'BA','BB','BC','BD','BE','BF','BG','BH','BI','BJ','BK','BL','BM','BN','BO','BP','BQ','BR','BS','BT','BU','BV','BW','BX','BY','BZ',
                'CA','CB','CC','CD','CE','CF','CG','CH','CI','CJ','CK','CL','CM','CN','CO','CP','CQ','CR','CS','CT','CU','CV','CW','CX','CY','CZ',
                'DA','DB','DC','DD','DE','DF','DG','DH','DI','DJ','DK','DL','DM','DN','DO','DP','DQ','DR','DS','DT','DU','DV','DW','DX','DY','DZ');
            for($i = 0; $i < $res['tr']; $i++) {
                for($j = 0; $j < $res['td']; $j++) {
                    $data[$i][$td[$j]] = $this->convert_str($res['data'][$i][$j]);
                }
            }
            fclose($handle); //关闭指针
        }
        return $data;
    }

    // 解析 CSV
    private function input_csv($handle){
        $n = 0;
        $td = 0;
        $out = array();
        setlocale(LC_ALL, 'zh_CN');
        while ($data = fgetcsv($handle, 10000)) {
            if(!$n){
                $td = count($data);
            }
            for($i = 0; $i < $td; $i++) {
                $out[$n][$i] = $data[$i];
            }
            $n++;
        }
        return array('tr'=>$n, 'td'=>$td, 'data'=>$out);
    }

    // 已知编码 - GB2312转UTF-8
    protected function iconv_str($str){
        return @iconv('GB2312','UTF-8//TRANSLIT//IGNORE',$str);
    }

    // 未知编码 - 转UTF-8
    protected function convert_str($str){
        $encode_arr=array('UTF-8','ASCII','GBK','GB2312','BIG5','JIS','eucjp-win','sjis-win','EUC-JP');
        $encode = @mb_detect_encoding($str, $encode_arr);
        return @mb_convert_encoding($str,"UTF-8",$encode);
    }

    /**
     * @fun:     数组集导出CSV文件
     * @author:  ZHL
     * @date:    2020-05-12
     * @param    array    $trList  数据集(二维数组)，
     * @param    string   $title 导出文件名(可为空)，
     * @param    array    $thList  导出文件列名(一维数组，键名为sql字段名（orcale大写）,值为execl列名/别称)，
     * @param    array    $e 屏蔽科学计数法(sql字段名，存在即屏蔽)
     * @param    bool     $hiddenNo   是否隐藏
     */
    public function export($trList, $thList, $title='', $e=array(), $hiddenNo = false){
        if(empty($trList) || empty($thList)){
            echo '<script type="text/javascript">alert("No Data Found");history.go(-1);</script>';exit;
        }
        if(count($trList)>5000){
            echo '<script type="text/javascript">alert("The data has exceeded 5000 records");history.go(-1);</script>';exit;
        }
        $title = $title ? $title : date('YmdHis');
        $filename = $title.".csv";

        $heads = array_values($thList);
        if(!$hiddenNo){
            array_unshift($heads, '编号');
        }

        foreach ($heads as $k => $v){
            $heads[$k] = iconv('utf-8', 'gbk', $v); //转utf-8
        }

        @ob_end_clean(); // 清空（擦除）缓冲区并关闭输出缓冲

        header("Content-type:text/csv"); //定义输出格式
        header("Content-type:application/vnd.ms-excel");
        header("Content-Disposition:attachment;filename=".$filename);
        header('Cache-Control:must-revalidate,post-check=0,pre-check=0,max-age=0');
        header('Expires:0');
        header('Pragma:public');

        //从数据库中获取数据，为了节省内存，不要把数据一次性读到内存，从句柄中一行一行读即可
        $fp = fopen('php://output', 'a');    // 表示直接输出到浏览器
        fputcsv($fp, $heads);         //将数据通过fputcsv写到文件句柄
        $cnt = 0;                     //计数器
        $limit = 1000;               //每隔$limit行，刷新输出buffer，不要太大，也不要太小
        //逐行取出数据，不浪费内存
        foreach($trList as $key=>$value){
            $cnt++;
            //刷新一下输出buffer，防止由于数据过多造成问题
            if($limit == $cnt){
                ob_flush();     // 把数据从PHP的缓冲（buffer）中释放出来。
                flush();        // 把不在缓冲（buffer）中的或者说是被释放出来的数据发送到浏览器。
                $cnt = 0;
            }

            $dataRow = array();
            $titleKeys = array_keys($thList);
            foreach($titleKeys as $k=>$v){
                if(in_array($v, $e)){
                    $dataRow[$k] = isset($value[$v]) ? $value[$v]."\t" : '';
                }else{
                    $dataRow[$k] = isset($value[$v]) ? $value[$v] : '';
                }
            }
            if(!$hiddenNo){
                array_unshift($dataRow, ($key+1));
            }
            $row = array();
            foreach($dataRow as $j => $v){
                $row[$j] = @iconv('utf-8', 'gbk//IGNORE', $v);
            }
            fputcsv($fp, $row);
        }
        exit;
    }
}
?>